using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;

namespace OracleInternal.ConnectionPool
{
	internal class RLB
	{
		internal static string s_pattern;

		internal static string s_patternSharding;

		public bool m_bStatus;

		public float m_version;

		public string m_database;

		public string m_service;

		internal string[] m_instances;

		public int[] m_percentages;

		public int[] m_rlbPercentages;

		private string m_timestamp;

		private string m_timeZone;

		internal DateTime m_dateTime;

		public int[] m_dispenseCounter;

		internal List<string> m_removedInstances;

		internal DateTime m_lastUpdateTime;

		public string m_id;

		private Random m_random;

		private static DateTimeFormatInfo s_dfi;

		internal object m_syncObject;

		private Dictionary<string, RLB> m_snapshotCache = new Dictionary<string, RLB>();

		private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

		private const int rwLockTimeout = 120000;

		static RLB()
		{
			s_pattern = "\\s*VERSION\\s*=\\s*(?<ver>.*?)\\s*database\\s*=\\s*(?<db>.*?)\\s*service\\s*=\\s*(?<svc>.*?)\\s*{\\s*(\\s*{\\s*instance\\s*=\\s*(?<inst>.*?)\\s+percent\\s*=\\s*(?<perc>.*?)\\s+(percentf\\s*=\\s*(?<percf>.*?)\\s+)*\\s*flag\\s*=\\s*(?<flag>.*?)\\s*}\\s*)*\\s*}\\s*timestamp\\s*=\\s*(?<ts>.*?)\\s*(timezone\\s*=\\s*(?<tz>.*?))*\\s*\\Z";
			s_patternSharding = "\\s*VERSION\\s*=\\s*(?<ver>.*?)\\s*database\\s*=\\s*(?<db>.*?)\\s*service\\s*=\\s*(?<svc>.*?)\\s*{\\s*(\\s*{\\s*instance\\s*=\\s*(?<inst>.*?)\\s+percent\\s*=\\s*(?<perc>.*?)\\s+(percentf\\s*=\\s*(?<percf>.*?)\\s+)*\\s*flags\\s*=\\s*(?<flag>.*?)\\s*aff\\s*=\\s*(?<aff>.*?)\\s*}\\s*)*\\s*}\\s*timestamp\\s*=\\s*(?<ts>.*?)\\s*(timezone\\s*=\\s*(?<tz>.*?))*\\s*\\Z";
			s_dfi = new DateTimeFormatInfo();
			s_dfi.ShortDatePattern = "yyyy-MM-dd";
			s_dfi.ShortTimePattern = "HH:mm:ss";
		}

		internal RLB(string message)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2304, OracleTraceClassName.RLB, OracleTraceFuncName.ctor);
			}
			try
			{
				m_random = new Random((int)DateTime.Now.Ticks);
				m_syncObject = new object();
				m_removedInstances = new List<string>();
				if (Parse(message))
				{
					m_id = (m_database + "|" + m_service).ToLowerInvariant();
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, (OracleTraceTag)268437504, OracleTraceClassName.RLB, OracleTraceFuncName.ctor, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2560, OracleTraceClassName.RLB, OracleTraceFuncName.ctor);
				}
			}
		}

		private RLB(RLB source, List<string> instanceNames)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				string text = string.Join(",", instanceNames);
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2304, OracleTraceClassName.RLB, OracleTraceFuncName.ctor, text);
			}
			try
			{
				m_random = new Random((int)DateTime.Now.Ticks);
				m_syncObject = new object();
				m_removedInstances = new List<string>();
				m_bStatus = source.m_bStatus;
				m_version = source.m_version;
				m_database = source.m_database;
				m_service = source.m_service;
				m_timestamp = source.m_timestamp;
				m_timeZone = source.m_timeZone;
				m_dateTime = source.m_dateTime;
				m_lastUpdateTime = source.m_lastUpdateTime;
				m_id = source.m_id;
				m_instances = new string[instanceNames.Count];
				m_rlbPercentages = new int[instanceNames.Count];
				m_percentages = new int[instanceNames.Count];
				m_dispenseCounter = new int[instanceNames.Count];
				int num = 0;
				int num2 = 0;
				for (int i = 0; i < source.m_instances.Length; i++)
				{
					for (int j = 0; j < instanceNames.Count; j++)
					{
						if (instanceNames[j] != null && source.m_instances[i].Equals(instanceNames[j].ToLowerInvariant()))
						{
							m_instances[num] = source.m_instances[i];
							m_rlbPercentages[num] = source.m_rlbPercentages[i];
							num2 += m_rlbPercentages[num];
							m_dispenseCounter[num] = source.m_dispenseCounter[i];
							num++;
							break;
						}
					}
				}
				for (int k = 0; k < instanceNames.Count; k++)
				{
					if (num2 > 0)
					{
						double a = (double)m_rlbPercentages[k] / (double)num2 * 100.0;
						m_rlbPercentages[k] = (int)Math.Round(a);
					}
					else
					{
						double a2 = 100.0 / (double)instanceNames.Count;
						m_rlbPercentages[k] = (int)Math.Round(a2);
					}
					if (k == 0)
					{
						m_percentages[k] = m_rlbPercentages[k] * 100;
					}
					if (k > 0)
					{
						m_percentages[k] = m_percentages[k - 1] + m_rlbPercentages[k] * 100;
					}
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, (OracleTraceTag)268437504, OracleTraceClassName.RLB, OracleTraceFuncName.ctor, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2560, OracleTraceClassName.RLB, OracleTraceFuncName.ctor);
				}
			}
		}

		internal string GetInstanceName(out int currentIndex)
		{
			int num = m_random.Next(10000);
			for (currentIndex = 0; currentIndex < m_percentages.Length; currentIndex++)
			{
				if (num <= m_percentages[currentIndex])
				{
					return m_instances[currentIndex];
				}
			}
			return m_instances[m_percentages.Length - 1];
		}

		internal RLB GetSnapshot(List<string> instanceNames)
		{
			RLB rLB = null;
			string key = string.Join("|", instanceNames);
			if (instanceNames == null)
			{
				return null;
			}
			if (rwLock.TryEnterUpgradeableReadLock(120000))
			{
				try
				{
					try
					{
						rLB = m_snapshotCache[key];
					}
					catch (KeyNotFoundException)
					{
					}
					if (rLB != null)
					{
						return rLB;
					}
					rLB = new RLB(this, instanceNames);
					if (rwLock.TryEnterWriteLock(120000))
					{
						try
						{
							m_snapshotCache[key] = rLB;
							return rLB;
						}
						finally
						{
							rwLock.ExitWriteLock();
						}
					}
					return rLB;
				}
				finally
				{
					rwLock.ExitUpgradeableReadLock();
				}
			}
			return rLB;
		}

		internal bool Parse(string message)
		{
			m_bStatus = true;
			if (message != null && message.Length != 0)
			{
				Match match = new Regex(s_pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(message);
				if (!match.Success)
				{
					match = new Regex(s_patternSharding, RegexOptions.IgnoreCase | RegexOptions.Singleline).Match(message);
				}
				m_service = match.Groups["svc"].Value.ToLowerInvariant();
				m_database = match.Groups["db"].Value.ToLowerInvariant();
				CaptureCollection captures = match.Groups["inst"].Captures;
				_ = match.Groups["sg"].Captures;
				CaptureCollection captures2 = match.Groups["perc"].Captures;
				CaptureCollection captures3 = match.Groups["flag"].Captures;
				m_timestamp = match.Groups["ts"].Value;
				m_timeZone = match.Groups["tz"].Value;
				float.TryParse(match.Groups["ver"].Value, out m_version);
				if (captures.Count == 0 || captures2.Count == 0 || captures3.Count == 0 || match.Groups["svc"].Captures.Count == 0)
				{
					m_bStatus = false;
				}
				else if (captures.Count != captures2.Count || captures2.Count != captures3.Count)
				{
					m_bStatus = false;
				}
				else if (m_service != null && m_service.Length == 0)
				{
					m_bStatus = false;
				}
				else if (m_timestamp == null || m_timestamp == string.Empty)
				{
					m_bStatus = false;
				}
				else if ((double)m_version <= 0.0)
				{
					m_bStatus = false;
				}
				else
				{
					DateTime dateTime = DateTime.Parse(m_timestamp, s_dfi);
					if (m_timeZone != string.Empty)
					{
						TimeSpan offset = TimeSpan.Parse(m_timeZone);
						m_dateTime = new DateTimeOffset(dateTime, offset).UtcDateTime;
					}
					else
					{
						m_dateTime = dateTime;
					}
				}
				if (m_bStatus)
				{
					lock (m_syncObject)
					{
						m_lastUpdateTime = DateTime.Now;
						m_percentages = new int[captures.Count];
						m_instances = new string[captures.Count];
						m_dispenseCounter = new int[captures.Count];
						m_rlbPercentages = new int[captures.Count];
						m_removedInstances.Clear();
					}
					for (int i = 0; i < captures.Count; i++)
					{
						m_instances[i] = captures[i].Value.ToLowerInvariant();
						m_rlbPercentages[i] = Convert.ToInt32(captures2[i].Value);
						double num = Convert.ToDouble(captures2[i].Value);
						if (i == 0)
						{
							m_percentages[i] = (int)(num * 100.0);
						}
						if (i > 0)
						{
							m_percentages[i] = m_percentages[i - 1] + (int)(num * 100.0);
						}
						if (ProviderConfig.m_bTraceLevelPrivate)
						{
							Trace.Write(OracleTraceLevel.Private, OracleTraceTag.RLB, OracleTraceClassName.RLB, OracleTraceFuncName.Parse, "Database=" + m_database + ";Service=" + m_service + ";Instance=" + m_instances[i] + ";Percentage=" + (int)num + ";Flag=" + captures3[i].Value + ";Timestamp=" + m_dateTime.ToString() + "\n");
						}
					}
				}
			}
			return m_bStatus;
		}
	}
}
